/*
 * Created on 2003/05/11
 *
 * To change the template for this generated file go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
package jp.sourceforge.akjrcp.image.clipboard;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author aki
 * 
 * To change the template for this generated type comment go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
public class AutoClipboardSave extends Thread{
	public static Log log = LogFactory.getLog(AutoClipboardSave.class);
	public static final  String IMAGE_JPEG="jpg";
	public static final  String IMAGE_PNG="png";
	private String fileType=IMAGE_PNG;
	//private int maxCount = 10000;
	private String prefix = "";
	//TODO:boolean overwrite;
	int count = 1;
	int figure = 4;
	// Image currentImage;
	private int waitTime = 50;
	private int sleepTime=100;

	

	//private static int[] oldPixels;

	private String saveDirectory = null;//System.getProperty("user.home")+"/"+"My Documents/";

	private boolean saving;
	
	//private List imageReferenceList=new ArrayList();
	
	private List AutoSaveListeners=new ArrayList();
	private boolean deleteOnExist=false;
	public void addAutoSaveListener(AutoSaveListener listener){
		AutoSaveListeners.add(listener);
	}
	
	public void removeAutoSaveListener(AutoSaveListener listener){
		AutoSaveListeners.remove(listener);
	}
	public void startSave(){
		if(!saving){
		log.info("start");
		saving=true;
		//this.setPriority(Thread.MAX_PRIORITY);
		this.start();
		//log.info("started");
		}
	}
	public void stopSave(){
		log.info("stop");
		saving=false;
	}
	public AutoClipboardSave(String saveDirectory) {
		this.saveDirectory=saveDirectory;
		if(saveDirectory==null){
			log.warn("saveDirectory is null");
		}
		
		
	}
	/*
	public void doSaveJpeg(BufferedImage img, String path) {
		try {
			ImageIO.write(img, "jpeg", new File(path));
		} catch (IOException e) {
		
			e.printStackTrace();
		}
	}

	public void doSavePng(BufferedImage img, String path) {
		try {
			ImageIO.write(img, "png", new File(path));
		} catch (IOException e) {
			
			e.printStackTrace();
		}
	}*/






	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	private File nextFile(){
		
		File file=null;
		do {
			String path = saveDirectory + prefix + toCounter(count)
			+ "."+fileType;
			file=new File(path);
			count++;
		}while(file.exists());
		
			
		return file;
	}
	
	public class ImageReference{
		private boolean availableDispose;
		private Image image;
		public boolean isAvailableDispose() {
			return availableDispose;
		}
		public void setAvailableDispose(boolean availableDispose) {
			this.availableDispose = availableDispose;
		}
		public Image getImage() {
			return image;
		}
		public void setImage(Image image) {
			this.image = image;
		}
	}
	
	/*
	public void updateReferences(){
		Iterator iter=imageReferenceList.iterator();
		while(iter.hasNext()){
			ImageReference reference=(ImageReference) iter.next();
			if(reference.isAvailableDispose()){
				
			}
		}
	}*/
	public class ImageSaver extends Thread{
		
		private File outputFile;
		private BufferedImage image;
		public ImageSaver(File outputFile,BufferedImage image){
			this.outputFile=outputFile;
			this.image=image;
		}
		public void run() {
			try {
			if(fileType.equals(IMAGE_PNG)){
				
					ImageIO.write(image, "png",outputFile);
				
			}else if(fileType.equals(IMAGE_JPEG)){
				ImageIO.write(image, "jpeg", outputFile);
			}
			} catch (IOException e) {
				log.warn(e.getMessage());
			}
			if(deleteOnExist){
				outputFile.deleteOnExit();
			}
			Iterator iter=AutoSaveListeners.iterator();
			while(iter.hasNext()){
				AutoSaveListener listener=(AutoSaveListener) iter.next();
				listener.imageSaved(outputFile);
			}
			image=null;//for gc?
		}
		
	}
	
	public void run() {
		log.info("run");
		
		while (saving) {
			BufferedImage img=null;
			try{
			img = ImageClipboardUtil.getClipboardImage();
			}catch(Exception e){
				//ignore
			}
		
			if (img != null) {
				
						File file= nextFile();
						log.info("save:"+file);
						new ImageSaver(file,img).start();
					//set string for finish clipboard
						StringSelection ss=new StringSelection("");	//should change image
						Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, ss);
						
					} else {
						try {
							//save if there nothing.
							Thread.sleep(sleepTime);
						} catch (InterruptedException e) {

							e.printStackTrace();
						}
					}

			
		}
		log.info("done");
	}
	/*
	public void run() {
		log.info("run");
		int gcindex=0;
		int gctarget=50;
		while (saving) {
			long startime=System.currentTimeMillis();
			BufferedImage img = ClipboardUtil.getClipboard();
			
			//log.info("image:"+img);
			if (img != null) {
				//log.info("image");
				try {
					Raster newRaster=img.getRaster();
					long prePixel=System.currentTimeMillis();
					int[] newPixels=newRaster.getPixels(0, 0, newRaster.getWidth(), newRaster
							.getHeight(), (int[]) null);
					System.out.println("topixel:"+(System.currentTimeMillis()-prePixel));
					prePixel=System.currentTimeMillis();
					for (int i = 0; i < img.getWidth(); i++) {
						for (int j = 0; j < img.getHeight(); j++) {
							img.getRGB(i, j);
						}
					}
					System.out.println("topixel2:"+(System.currentTimeMillis()-prePixel));
					long compare=System.currentTimeMillis();
					if (oldPixels == null || !ClipboardUtil.isSameImage(oldPixels, newPixels)) {
						
						long checkend=System.currentTimeMillis();
						log.info("compare:"+(compare-startime));
						
						File file= nextFile();
						log.info("save:"+file);
						//System.out.println(file.getAbsolutePath());
						//file.mkdirs();
						//long beforesave=System.currentTimeMillis();
						new ImageSaver(file,img).start();
						
						//System.out.println("save:"+(System.currentTimeMillis()-beforesave));
						oldPixels=null;//is it work?
						oldPixels = newPixels;
						

						
					} else {
						try {
							//save if there nothing.
							Thread.sleep(sleepTime);
						} catch (InterruptedException e) {

							e.printStackTrace();
						}
					}
				} catch (Exception e1) {

					e1.printStackTrace();
				}

			}else{
				oldPixels=null;
				try {
					//log.info("sleep");
					gcindex++;
					if(gcindex==gctarget){
					System.gc();
					gcindex=0;
					}
					Thread.sleep(sleepTime);
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
			}

		}
		log.info("done");
	}*/

	public int getWaitTime() {
		return waitTime;
	}

	public void setWaitTime(int waitTime) {
		this.waitTime = waitTime;
	}

	public String getSaveDirectory() {
		return saveDirectory;
	}

	public void setSaveDirectory(String baseDirectory) {
		this.saveDirectory = baseDirectory;
	}

	private String toCounter(int index){
		
		String v=""+index;
		while(v.length()<figure){
			v="0"+v;
		}
		return v;
	}
	public int getFigure() {
		return figure;
	}
	public void setFigure(int figure) {
		this.figure = figure;
	}
	public String getFileType() {
		return fileType;
	}
	public void setFileType(String fileType) {
		this.fileType = fileType;
	}
	public String getPrefix() {
		return prefix;
	}
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}
	public boolean isSaving() {
		return saving;
	}
	public void setSaving(boolean saving) {
		this.saving = saving;
	}
	public int getSleepTime() {
		return sleepTime;
	}
	public void setSleepTime(int sleepTime) {
		this.sleepTime = sleepTime;
	}

	public boolean isDeleteOnExist() {
		return deleteOnExist;
	}

	public void setDeleteOnExist(boolean deleteOnExist) {
		this.deleteOnExist = deleteOnExist;
	}
}
